package com.qs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qs.constant.RedisConstant;
import com.qs.mapper.*;
import com.qs.pojo.entity.*;
import com.qs.pojo.enums.LoginTypeStatus;
import com.qs.pojo.enums.PayStatus;
import com.qs.pojo.vo.GoodsStockLockVo;
import com.qs.service.IAsyncService;
import com.qs.utils.LoginTypeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ClassName: AsyncServiceImpl
 * Package: com.qs.service.impl
 * Description:
 *
 * @Author: @weixueshi
 * @Create: 2023/12/8 - 10:42
 * @Version: v1.0
 */
@Slf4j
//@Async("asyncExecutor")
@Service
@RequiredArgsConstructor
public class AsyncServiceImpl implements IAsyncService {

    private final ReentrantLock lock = new ReentrantLock();

    private final GoodsMapper goodsMapper;

    private final RedisTemplate redisTemplate;

    private final CartMapper cartMapper;

    private final PayInfoMapper payInfoMapper;

    private final UserGoodsLogMapper userGoodsLogMapper;

    private final OrderCartMapper orderCartMapper;

    private final OnlineMapper onlineMapper;

    @Override
    public void deductionStock(Integer[] cartId,String orderId) {
        for (int i = 0; i < cartId.length; i++) {
            List<GoodsStockLockVo> stockLockVoList = (List<GoodsStockLockVo>) redisTemplate.opsForValue().get(RedisConstant.GOODS_STOCK_LOCK + orderId);
            if(!CollectionUtils.isEmpty(stockLockVoList)){
                //将商品的数量扣减
                //将锁定的商品数量扣减
                //增加商品销量
                stockLockVoList.stream().forEach(stockLockVo -> {
                    Goods goods = goodsMapper.selectById(stockLockVo.getGoodsId());
                    goods.setNumber(goods.getNumber() - stockLockVo.getNumbers());
                    goods.setLockStock(goods.getLockStock() - stockLockVo.getNumbers());
                    goods.setSale(goods.getSale() + stockLockVo.getNumbers());
                    goodsMapper.updateById(goods);
                });
            }
            //将redis缓存的stockLockVo数据删除
            redisTemplate.delete(RedisConstant.GOODS_STOCK_LOCK + orderId);
        }
    }

    @Override
    public void deleteCartSelected(Integer[] cartId) {
        for (int i = 0; i < cartId.length; i++) {
            cartMapper.deleteById(cartId[i]);
        }
    }

    @Override
    public void updatePayInfo(String orderId,String paymentType) {
        QueryWrapper<PayInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",orderId);
        PayInfo payInfo = payInfoMapper.selectOne(queryWrapper);
        if(payInfo != null){
            payInfo.setOrderStatus(PayStatus.HAVE_PAY);
            payInfo.setType(paymentType);
            payInfoMapper.updateById(payInfo);
        }
    }

    @Override
    public void saveUserGoodsLog(String orderId, Integer userId, Integer[] cartIds) {
        if(cartIds.length > 0){
            for (int i = 0; i < cartIds.length; i++) {
                Cart cart = cartMapper.selectById(cartIds[i]);
                Goods goods = goodsMapper.selectById(cart.getGoodsId());
                QueryWrapper<UserGoodsLog> wrapper = new QueryWrapper<>();
                wrapper.eq("order_id", orderId);
                wrapper.eq("store_id", goods.getStoreId());
                wrapper.eq("goods_id", goods.getId());
                UserGoodsLog selectOne = userGoodsLogMapper.selectOne(wrapper);
                if(null == selectOne){
                    UserGoodsLog userGoodsLog = new UserGoodsLog();
                    userGoodsLog.setOrderId(orderId);
                    userGoodsLog.setUserId(userId);
                    userGoodsLog.setGoodsId(goods.getId());
                    userGoodsLog.setStoreId(goods.getStoreId());
                    userGoodsLogMapper.insert(userGoodsLog);
                }
            }
        }
    }

    @Override
    public void savePayInfo(String orderId, Integer userId) {
        PayInfo payInfo = new PayInfo();
        payInfo.setOrderId(orderId);
        payInfo.setOrderStatus(PayStatus.WAIT_PAY);
        payInfo.setUserId(userId);
        payInfoMapper.insert(payInfo);
    }

    @Override
    public void saveOrderCart(String orderId, Integer userId, List<Integer> cartIds) {
        if(!CollectionUtils.isEmpty(cartIds) && orderId != null && userId != null){
            cartIds.stream().forEach(cartId -> {
                OrderCart orderCart = new OrderCart();
                Cart cart = cartMapper.selectById(cartId);
                orderCart.setOrderId(orderId);
                orderCart.setUserId(userId);
                orderCart.setCartId(cartId);
                orderCartMapper.insert(orderCart);
            });
        }
    }

    @Override
    public void deleteOrderCart(String orderId, Integer userId) {
        QueryWrapper<OrderCart> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id",orderId);
        wrapper.eq("user_id",userId);
        orderCartMapper.delete(wrapper);
    }

    @Override
    public void deleteOrderIdExpire(String orderId) {
        QueryWrapper<PayInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id",orderId);
        payInfoMapper.delete(wrapper);
    }

    @Override
    public void deductionLockStock(List<Integer> cartIds, String orderId) {
        for (int i = 0; i < cartIds.size(); i++) {
            List<GoodsStockLockVo> stockLockVoList = (List<GoodsStockLockVo>) redisTemplate.opsForValue().get(RedisConstant.GOODS_STOCK_LOCK + orderId);
            if(!CollectionUtils.isEmpty(stockLockVoList)){
                //将锁定的商品数量扣减
                stockLockVoList.stream().forEach(stockLockVo -> {
                    Goods goods = goodsMapper.selectById(stockLockVo.getGoodsId());
                    goods.setLockStock(goods.getLockStock() - stockLockVo.getNumbers());
                    goodsMapper.updateById(goods);
                });
            }
            //将redis缓存的stockLockVo数据删除
            redisTemplate.delete(RedisConstant.GOODS_STOCK_LOCK + orderId);
        }
    }

    @Override
    public void  changeUserOnlineStatus(HttpServletRequest request, int userId) {
        //异步方法上锁，否则多个线程进来会导致同一个用户新增多个Online
        lock.lock();
        try {
            String loginType = LoginTypeUtil.getLoginType(request);
            QueryWrapper<Online> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId);
            Online online = onlineMapper.selectOne(wrapper);
            //说明是才登录
            if(null == online) {
                online = new Online();
                online.setStatus(LoginTypeStatus.ON_LINE);
                online.setUserId(userId);
                online.setLoginType(loginType);
                onlineMapper.insert(online);
            }else {
                if(online.getStatus().getCode().intValue() != LoginTypeStatus.ON_LINE.getCode()){
                    online.setStatus(LoginTypeStatus.ON_LINE);
                    online.setLoginType(loginType);
                    onlineMapper.updateById(online);
                }else {
                    online.setLoginType(loginType);
                    onlineMapper.updateById(online);
                }
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void changeUserOfflineStatus(int userId) {
        QueryWrapper<Online> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        Online online = onlineMapper.selectOne(wrapper);
        if(null != online) {
            online.setStatus(LoginTypeStatus.OFF_LINE);
            onlineMapper.updateById(online);
        }
    }

    @Override
    public void incrementWithGoods(Integer id) {
        lock.lock();
        try {
            Goods goods = goodsMapper.selectById(id);
            goods.setBrowse(goods.getBrowse() + 1);
            goodsMapper.updateById(goods);
        }finally {
            lock.unlock();
        }
    }
}
